package util.resource;

import java.util.ArrayList;
import org.newdawn.slick.Game;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;

/**
 * A Sprite class contains multiple images that can be played in an animation if you wish. It's
 * a replacement for Slick2D's Animation class. It pretty much fills the same functionality with
 * all the unneeded methods removed.
 * 
 * @author Logan
 */
public class Sprite
{
	private ArrayList<Image> imageList;
	
	private float imageIndex=0,imageSpeed=1;
	private int width=0,height=0;
	private float xOffset=0,yOffset=0;
	
	/**
	 * Creates a new Sprite object with no frames. If you attempt to render without adding frames,
	 * you will see nothing on the screen.
	 */
	public Sprite()
	{
		imageList=new ArrayList<Image>();
	}
	
	/**
	 * Creates a new Sprite object with a single frame. It will display as simply a still
	 * image.
	 * @param image - the image to set to the first and only frame.
	 */
	public Sprite(Image image)
	{
		this();
		
		addFrame(image);
	}
	
	/**
	 * Creates a new Sprite object, except using a strip. This strip is one frame high and
	 * however many frames as desired wide.
	 * @param image - the image that contains the strip.
	 * @param frameWidth - the width of each individual frame, in pixels.
	 */
	public Sprite(Image image,int frameWidth)
	{
		this();
		
		for(int i=0;i<image.getWidth();i+=frameWidth)
			addFrame(image.getSubImage(i,0,frameWidth,image.getHeight()));
	}
	
	/**
	 * Adds a frame to the current animation.
	 * @param image - the frame to add.
	 */
	public void addFrame(Image image)
	{
		imageList.add(image);
		
		width=Math.max(width,image.getWidth());
		height=Math.max(height,image.getHeight());
	}
	
	/**
	 * Renders the sprite with no effects.
	 * @param x - the x position in which to render the image.
	 * @param y - the y position in which to render the image.
	 * @param gc - the current game container.
	 * @param game - the current state based game
	 * @param g - the current graphics context.
	 */
	public void render(float x,float y,GameContainer gc,Game game,Graphics g)
	{
		if(imageList.size()>0)
			imageList.get((int)imageIndex).draw(x-xOffset,y-yOffset);
	}
	
	/**
	 * Simply returns the image that would normally be displayed by a call to render(...).
	 * This is useful, for instance, if you wish to draw the sprite with a certain effect
	 * that exists within Slick's image class. For example, if you want to draw the image
	 * with an alpha or if you want to draw it with a specific size.
	 * @return the current animation frame image
	 */
	public Image getImage()
	{
		return imageList.get((int)imageIndex);
	}
	
	/**
	 * This important method updates the current animation frame. Without calling this every step,
	 * the animation will not update.
	 * @param gc - the current game container.
	 * @param game - the current game.
	 */
	public void update(GameContainer gc,Game game)
	{
		imageIndex+=imageSpeed;
		if(imageIndex>=imageList.size())
			imageIndex%=imageList.size();
	}
	
	/**
	 * Sets the speed of the animation.
	 * @param speed - number to increment the image index every update.
	 */
	public void setImageSpeed(float speed)
	{		
		imageSpeed=speed;
	}
	
	/**
	 * Changes the image index to a specific value.
	 * @param imageIndex - value we are forcing the image index to.
	 */
	public void setImageIndex(int imageIndex)
	{
		this.imageIndex=imageIndex%length();
	}
	
	/**
	 * Returns the number of frames in the animation.
	 * @return number of frames in the animation
	 */
	public int length()
	{
		return imageList.size();
	}
	
	/**
	 * Centers the origin of the sprite relative to it's current width and current height.
	 */
	public void centerOrigin()
	{
		xOffset=width/2;
		yOffset=height/2;
	}
	
	/**
	 * Sets the origin of the sprite to a specific value.
	 * @param xOffset - the x to offset the origin by (default: 0).
	 * @param yOffset - the y to offset the origin by (default: 0).
	 */
	public void setOrigin(int xOffset,int yOffset)
	{
		this.xOffset=xOffset;
		this.yOffset=yOffset;
	}
	
	/**
	 * Gets the current width of the sprite. It may change as more frames are added.
	 * @return the width of the sprite
	 */
	public float getWidth()
	{
		return width;
	}
	
	/**
	 * Gets the current height of the sprite. It may change as more frames are added.
	 * @return the height of the sprite
	 */
	public float getHeight()
	{
		return height;
	}
}
